package com.geovis.emergency.spd.controller.pc;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.geovis.common.core.api.Result;
import com.geovis.common.core.constant.SwaggerConstants;
import com.geovis.common.core.controller.BaseController;
import com.geovis.common.mybatis.page.PageParam;
import com.geovis.common.mybatis.page.PageResult;
import com.geovis.emergency.spd.biz.filing.service.ITbPlanFilingsService;
import com.geovis.emergency.spd.biz.pc.service.*;
import com.geovis.emergency.spd.biz.system.service.ISystemDeptService;
import com.geovis.emergency.spd.cache.DictCache;
import com.geovis.emergency.spd.cache.RegionCache;
import com.geovis.emergency.spd.entity.filing.pojo.GroupStatTypeEnum;
import com.geovis.emergency.spd.entity.pc.entity.*;
import com.geovis.emergency.spd.entity.pc.pojo.constant.PcDisasterConstant;
import com.geovis.emergency.spd.entity.pc.pojo.dto.PcPlanQueryDTO;
import com.geovis.emergency.spd.entity.pc.pojo.dto.PcPlanSaveDTO;
import com.geovis.emergency.spd.entity.pc.pojo.dto.PcPlanUpdateDTO;
import com.geovis.emergency.spd.entity.pc.pojo.vo.PcPlanDetailVO;
import com.geovis.emergency.spd.entity.pc.pojo.vo.PcPlanGroupByVO;
import com.geovis.emergency.spd.entity.pc.pojo.vo.PcPlanResponseRecommendVO;
import com.geovis.emergency.spd.entity.pc.pojo.vo.PcPlanVO;
import com.geovis.emergency.spd.entity.system.entity.SystemDept;
import com.geovis.emergency.spd.entity.system.entity.SystemRegion;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.NotNull;
import java.lang.reflect.Array;
import java.util.*;

/**
 * <p>
 * 应急预案指挥模块 - 预案管理 前端控制器
 * </p>
*
* @author Lonsho
* @since 2022-06-17
*/
@RestController
@RequestMapping("/pc/plan")
@RequiredArgsConstructor
@Api(value = "应急预案指挥模块 - 预案管理接口", tags = "应急预案指挥模块 - 预案管理接口")
@Slf4j
@Validated
public class PcPlanController extends BaseController<IPcPlanService> {
    private final IPcPlanResponseService pcPlanResponseService;
    private final IPcPlanStructureService pcPlanStructureService;
    private final ISystemDeptService systemDeptService;

    private final IPcPlanDutyOrgService pcPlanDutyOrgService;
    private final IPcPlanDutyDeptService pcPlanDutyDeptService;
    private final IPcPlanDutyOrgDeptService pcPlanDutyOrgDeptService;

    private final ITbPlanFilingsService tbPlanFilingsService;

    @ApiOperationSupport(order = 1)
    @ApiOperation(value = SwaggerConstants.SAVE_VALUE, notes = SwaggerConstants.SAVE_VALUE)
    @PostMapping({"/save"})
    public Result save(@RequestBody @Validated PcPlanSaveDTO saveDTO) {
        this.baseService.savePcPlan(saveDTO);
        return Result.ok();
    }

    @ApiOperationSupport(order = 2)
    @ApiOperation(value = SwaggerConstants.UPDATE_VALUE, notes = SwaggerConstants.UPDATE_NOTES)
    @PostMapping({"/update"})
    public Result update(@RequestBody @Validated PcPlanUpdateDTO updateDTO) {
        //如果要停用，校验预案是否已绑定未停用的灾害
        if("0".equals(updateDTO.getDataStatus()))
        {
            Boolean check=baseService.checkInDisaster(Arrays.asList(updateDTO.getId()),false);
            if(check)
            {
                return Result.failed("该预案已绑定正在使用的灾害事件，无法停用");
            }
        }
        this.baseService.updatePcPlan(updateDTO);
        return Result.ok();
    }

    @ApiOperationSupport(order = 3)
    @ApiOperation(value = SwaggerConstants.LIST_PAGE_VALUE, notes = SwaggerConstants.LIST_PAGE_VALUE)
    @PostMapping("/listPage")
    public Result<PageResult<PcPlanVO>> listPage(@RequestBody PageParam<PcPlanQueryDTO> pageParam) {
        PcPlanQueryDTO queryDTO = pageParam.getQuery();
        IPage<PcPlan> pcPlanPage = pageParam.buildPage();
        IPage<PcPlanVO> pcPlanVOPage = pageParam.buildPage();
        pcPlanVOPage.setRecords(new ArrayList<PcPlanVO>());
        //分页查询
        baseService.page(pcPlanPage,baseService.getWrapper(queryDTO));

        BeanUtil.copyProperties(pcPlanPage,pcPlanVOPage,"records");
        //转换VO
        for (int i = 0; i <pcPlanPage.getRecords().size() ; i++) {
            PcPlanVO pcPlanVO=new PcPlanVO();
            BeanUtil.copyProperties(pcPlanPage.getRecords().get(i),pcPlanVO);
            pcPlanVO.setTypeName(DictCache.getDictValue(PcDisasterConstant.DISASTER_TYPE,pcPlanVO.getType()));

            pcPlanVOPage.getRecords().add(pcPlanVO);
        }

        return Result.ok(new PageResult<PcPlanVO>(pcPlanVOPage));
    }

    @ApiOperationSupport(order = 4)
    @ApiOperation(value = SwaggerConstants.LIST_VALUE, notes = SwaggerConstants.LIST_VALUE)
    @PostMapping("/getList")
    public Result<List<PcPlan>> getList(@RequestBody @Validated PcPlanQueryDTO pageParam) {
        return Result.ok(baseService.list(baseService.getWrapper(pageParam)));
    }

    @ApiOperationSupport(order = 5)
    @ApiOperation(value = SwaggerConstants.GET_BY_ID_VALUE, notes = SwaggerConstants.GET_BY_ID_NOTES)
    @PostMapping("/getDetail")
    public Result<PcPlanDetailVO> getDetail(@ApiParam(value="预案id",name="pcPlanId") String pcPlanId) {
        return Result.ok(baseService.detailVO(pcPlanId));
    }

    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "批量删除", notes = "批量删除数据")
    @ApiImplicitParams({@ApiImplicitParam(name = "idList", value = "删除id的list", required = true, dataType = "java.util.Set", paramType = "body")})
    @PostMapping("/removeByIdList")
    @Transactional
    public Result removeByIdList(@NotNull(message = "删除的id集合不能为空") @RequestBody Set<String> idList) {
        //校验预案是否已绑定灾害事件
        Boolean check=baseService.checkInDisaster(new ArrayList<>(idList),true);
        if(check)
        {
            return Result.failed("预案已绑定灾害事件，无法删除");
        }

        idList.forEach(id->{
            this.pcPlanDutyDeptService.remove(Wrappers.lambdaQuery(PcPlanDutyDept.class).eq(PcPlanDutyDept::getPcPlanId,id));
            this.pcPlanDutyOrgService.remove(Wrappers.lambdaQuery(PcPlanDutyOrg.class).eq(PcPlanDutyOrg::getPcPlanId,id));
            this.pcPlanDutyOrgDeptService.remove(Wrappers.lambdaQuery(PcPlanDutyOrgDept.class).eq(PcPlanDutyOrgDept::getPcPlanId,id));
            this.pcPlanStructureService.remove(Wrappers.lambdaQuery(PcPlanStructure.class).eq(PcPlanStructure::getPcPlanId,id));
        });

        baseService.removeBatchByIds(idList);
        return Result.ok();
    }

    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "预案备案-按类型统计", notes = "按类型统计")
    @PostMapping("/statistics/type")
    public Result<List<PcPlanGroupByVO>> groupByType() {
        return Result.ok(tbPlanFilingsService.groupBy(GroupStatTypeEnum.TYPE));
    }

    @ApiOperationSupport(order = 8)
    @ApiOperation(value = "按区域统计", notes = "按区域统计")
    @PostMapping("/statistics/region")
    public Result<List<PcPlanGroupByVO>> groupByRegion() {
        QueryWrapper<PcPlan> wrapper = new QueryWrapper<PcPlan>()
                .select("count(1) as count,region_code").groupBy("region_code");
        List<Map<String,Object>> mapList=baseService.listMaps(wrapper);

        //统计不再写xml,直接通过for循环赋值，数量不多，基本不影响效率
        List<PcPlanGroupByVO> retList=new ArrayList<PcPlanGroupByVO>();
        for (int i = 0; i < mapList.size(); i++) {
            PcPlanGroupByVO vo=new PcPlanGroupByVO();
            SystemRegion systemRegion=RegionCache.getByCode(mapList.get(i).get("region_code").toString());
            vo.setTitle(systemRegion==null?mapList.get(i).get("region_code").toString():systemRegion.getName());
            vo.setCount(Integer.parseInt(mapList.get(i).get("count").toString()));
            retList.add(vo);
        }

        return Result.ok(retList);
    }

    @ApiOperationSupport(order = 8)
    @ApiOperation(value = "预案备案-按等级统计", notes = "按等级统计")
    @PostMapping("/statistics/level")
    public Result<List<PcPlanGroupByVO>> groupByLevel() {
        return Result.ok(tbPlanFilingsService.groupBy(GroupStatTypeEnum.LEVEL));
    }

    @ApiOperationSupport(order = 9)
    @ApiOperation(value = "预案备案-按部门统计", notes = "按部门统计")
    @PostMapping("/statistics/dept")
    public Result<List<PcPlanGroupByVO>> groupByDept() {
        return Result.ok(tbPlanFilingsService.groupBy(GroupStatTypeEnum.DEPT));
    }


    @ApiOperationSupport(order = 10)
    @ApiOperation(value = "根据灾害类型、等级、用户分组获取响应预案推荐", notes = "根据灾害类型、等级、用户分组获取响应预案推荐")
    @PostMapping("/response/recommend")
    public Result<List<PcPlanResponse>> responseRecommend(@RequestBody PcPlanResponseRecommendVO recommendVO) {
        return Result.ok( pcPlanResponseService.list(pcPlanResponseService.getRecommend(recommendVO)));
    }
}
